package com.train.redis.core.support;


import com.train.common.utils.string.FormatterUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class RedisSupport {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 字符串存储, 带过期时间
     * @param key
     * @param value
     * @param expire
     * @param timeUnit
     */
    public void addValue(String key, Object value, Long expire, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, expire, timeUnit);
    }

    /**
     * 字符串存储
     * @param format
     * @param key
     * @param value
     */
    public void addValue(String format, String key, Object value) {
        redisTemplate.opsForValue().set(FormatterUtils.format(format, key), value);
    }

    /**
     * 字符串存储, 带过期时间
     * @param format
     * @param value
     * @param expire
     * @param timeUnit
     * @param keys
     */
    public void addValue(Object value, Long expire, TimeUnit timeUnit, String format, Object... keys) {
        redisTemplate.opsForValue().set(FormatterUtils.format(format, keys), value, expire, timeUnit);
    }

    /**
     * 字符串存储, 带过期时间
     * @param format
     * @param key
     * @param value
     * @param expire
     * @param timeUnit
     */
    public void addValue(String format, String key, Object value, Long expire, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(FormatterUtils.format(format, key), value, expire, timeUnit);
    }

    /**
     * 字符串获取值
     * @param format
     * @param keys
     */
    public Object getValue(String format, Object... keys) {
        return redisTemplate.opsForValue().get(FormatterUtils.format(format, keys));
    }

    /**
     * 删除单个redis值
     * @param format
     * @param keys
     * @return
     */
    public Boolean delete(String format, Object... keys) {
        return redisTemplate.delete(FormatterUtils.format(format, keys));
    }

    /**
     * 删除多个redis值
     * @param format
     * @param keys
     * @return
     */
    public Boolean delete(String format, Collection<String> keys) {
        List<String> formatKeys = keys.stream().map(key -> FormatterUtils.format(format, key)).collect(Collectors.toList());
        Long delete = redisTemplate.delete(formatKeys);
        if (delete == null) {
            return false;
        }
        return delete.equals((long) keys.size());
    }

    /**
     * 存储list集合
     * @param format
     * @param key
     * @param value
     * @return
     */
    public Long addList(String format, String key, Object value) {
        Long length = redisTemplate.opsForList().rightPush(FormatterUtils.format(format, key), value);
        return length == null ? 0 : length;
    }

    /**
     * 获取所有list集合
     * @param format
     * @param key
     * @return
     */
    public List<Object> getList(String format, String key) {
        return getList(format, key ,0L, -1L);
    }

    /**
     * 根据范围获取list集合
     * @param format
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<Object> getList(String format, String key, Long start, Long end) {
        return redisTemplate.opsForList().range(FormatterUtils.format(format, key), start, end);
    }

    /**
     * 添加set集合
     * @param format
     * @param key
     * @param set
     * @return
     */
    public Long addSet(String format, String key, Set<Object> set) {
        Long length = redisTemplate.opsForSet().add(FormatterUtils.format(format, key), set);
        return length == null ? 0 : length;
    }

    /**
     * 获取set集合
     * @param format
     * @param key
     * @return
     */
    public Set<Object> getSet(String format, String key) {
        return redisTemplate.opsForSet().members(FormatterUtils.format(format, key));
    }

    /**
     * 添加多个hash
     * @param format
     * @param key
     * @param map
     */
    public void addHash(String format, String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(FormatterUtils.format(format, key), map);
    }

    /**
     * 获取所有map
     * @param format
     * @param key
     * @return
     */
    public Map<Object, Object> getHash(String format, String key) {
        return redisTemplate.opsForHash().entries(FormatterUtils.format(format, key));
    }

    /**
     * 添加单个hash
     * @param format
     * @param key
     * @param hFormat
     * @param hKey
     * @param value
     */
    public void addHash(String format, String key, String hFormat, String hKey, Object value) {
        redisTemplate.opsForHash().put(FormatterUtils.format(format, key), FormatterUtils.format(hFormat, hKey), value);
    }

    /**
     * 获取单个hash
     * @param format
     * @param key
     */
    public Object getHash(String format, String key, String hFormat, String hKey) {
        return redisTemplate.opsForHash().get(FormatterUtils.format(format, key), FormatterUtils.format(hFormat, hKey));
    }

    /**
     * 获取多个hash值
     * @param format
     * @param key
     * @param hFormat
     * @param hKeys
     * @return
     */
    public List<Object> getHash(String format, String key, String hFormat, List<String> hKeys) {
        List<Object> hKeyList = hKeys.stream().map(hKey -> FormatterUtils.format(hFormat, hKey)).collect(Collectors.toList());
        return redisTemplate.opsForHash().multiGet(FormatterUtils.format(format, key), hKeyList);
    }

    /**
     * 删除多个hash
     * @param format
     * @param key
     * @param hFormat
     * @param hKeys
     * @return
     */
    public Long delete(String format, String key, String hFormat, List<String> hKeys) {
        List<Object> hKeyList = hKeys.stream().map(hKey -> FormatterUtils.format(hFormat, hKey)).collect(Collectors.toList());
        return redisTemplate.opsForHash().delete(FormatterUtils.format(format, key), hKeyList);
    }

    /**
     * 获取key列表
     * @param pattern
     * @return
     */
    public Collection<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 设置过期时间
     * @param key
     * @param expireTime
     * @param timeUnit
     * @return
     */
    public Boolean expire(String format, String key, Long expireTime, TimeUnit timeUnit) {
        return redisTemplate.expire(FormatterUtils.format(format, key), expireTime, timeUnit);
    }

    /**
     * 执行lua脚本
     * @param script
     * @param keys
     * @param values
     * @return
     * @param <T>
     */
    public <T> T executeScript(RedisScript<T> script, List<String> keys, Object... values) {
        return redisTemplate.execute(script, keys, values);
    }

    /**
     * 设置和获取分布式锁
     * @param keyFormat
     * @param lockKeys
     * @param lockValue
     * @param expireTime
     * @param timeUnit
     * @return
     */
    public Boolean setLock(String keyFormat, Object lockValue, Long expireTime, TimeUnit timeUnit, Object... lockKeys) {
        if (timeUnit == null) {
            timeUnit = TimeUnit.SECONDS;
        }
        return setLock(FormatterUtils.format(keyFormat, lockKeys), lockValue, expireTime, timeUnit);
    }

    /**
     * 设置和获取分布式锁
     * @param lockKey
     * @param lockValue
     * @param expireTime
     * @param timeUnit
     * @return
     */
    public Boolean setLock(String lockKey, Object lockValue, Long expireTime, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expireTime, timeUnit);
    }

    /**
     * 获取分布式锁
     * @param keyFormat
     * @param lockKeys
     * @return
     */
    public Object getLock(String keyFormat, Object... lockKeys) {
        return redisTemplate.opsForValue().get(FormatterUtils.format(keyFormat, lockKeys));
    }

    /**
     * 获取分布式锁
     * @param lockKey
     * @return
     */
    public Object getLock(String lockKey) {
        return redisTemplate.opsForValue().get(lockKey);
    }

    /**
     * 减少值
     * @param format
     * @param decrement
     * @param keys
     * @return
     */
    public Long decrement(String format, long decrement, Object... keys) {
        return redisTemplate.opsForValue().decrement(FormatterUtils.format(format, keys), decrement);
    }

    /**
     * 模糊匹配key删除
     */
    public void delete(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }

    /**
     * 前缀匹配key是否存在
     */
    public Boolean exists(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        return keys != null && !keys.isEmpty();
    }

}
